/*
*
* Copyright (c) 2011 Vaulting Systems International
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy 
* of this software and associated documentation files (the "Software"), to deal 
* in the Software without restriction, including without limitation the rights 
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
* of the Software, and to permit persons to whom the Software is furnished to do  
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all  
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE  
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package com.ekeyman.securesavelib.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.SecureRandom;
import java.security.Security;
import java.util.UUID;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.digest.DigestUtils;

import com.ekeyman.securesavelib.dto.EncryptionKeys;

public class SecureSaveUtils {

	public static String getTemporaryDirectory(){
		// This is platform dependent
		return System.getProperty("jboss.server.temp.dir");
	}
	
	public static String getUniqueIdentifier(){
		UUID i = UUID.randomUUID();
		String s = i.toString();
		return s.replaceAll("-", "").toLowerCase();
	}
	
	/*
	 * Encrypt using secret key encryption
	 */
	public static void encrypt(EncryptionKeys encryptionKeys, File uploadedFile, File encryptedFile) throws Exception{
    	Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); 
	    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC"); 
	    SecretKeySpec encryptionKey = new SecretKeySpec(encryptionKeys.getKeyBytes(), "AES");
	    cipher.init(Cipher.ENCRYPT_MODE, encryptionKey);
	    
	    InputStream clearTextFis = new FileInputStream(uploadedFile);
	    OutputStream cipherTextFos = new FileOutputStream(encryptedFile);

	    // Bytes written to out will be encrypted
	    cipherTextFos = new CipherOutputStream(cipherTextFos, cipher);
        // Read in the cleartext bytes and write to out to encrypt
	    byte[] buf = new byte[4096];
        int numRead = 0;
        while ((numRead = clearTextFis.read(buf)) >= 0) {
        	cipherTextFos.write(buf, 0, numRead);
        }
        cipherTextFos.close();
	}
	
	/*
	 * Decrypt using secret key encryption 
	 */
	public static void decrypt(EncryptionKeys encryptionKeys, InputStream s3is, File decryptedFile) throws Exception{
    	Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); 
	    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC"); 
	    SecretKeySpec encryptionKey = new SecretKeySpec(encryptionKeys.getKeyBytes(), "AES");
	    cipher.init(Cipher.DECRYPT_MODE, encryptionKey);

	    OutputStream decryptedFos = new FileOutputStream(decryptedFile);
		
		s3is = new CipherInputStream(s3is, cipher);
        
        int numRead = 0;
        byte[] buf = new byte[4096];
        while ((numRead = s3is.read(buf)) >= 0) {
        	decryptedFos.write(buf, 0, numRead);
        }
        decryptedFos.close();

	}
	
	/*
	 * Encrypt using password based encryption
	 */
	
	public static void encrypt(EncryptionKeys encryptionKeys, File uploadedFile, File encryptedFile, String passphrase) throws Exception{
    	Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); 
       
    	SecureRandom random = new SecureRandom();
    	String secretKeyType = "PBEWITHSHA256AND256BITAES-CBC-BC";
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(secretKeyType); 
        
        PBEKeySpec eKeySpec = new PBEKeySpec(DigestUtils.md5Hex(passphrase).toCharArray(), encryptionKeys.getSaltBytes(), 
        		encryptionKeys.getIterationCount(), 1024); 
        SecretKey eKey = keyFactory.generateSecret(eKeySpec); 
        Cipher eCipher = Cipher.getInstance("AES/CTR/NOPADDING"); 
        IvParameterSpec eIvParameterSpec =  new IvParameterSpec(encryptionKeys.getIvBytes()); 
        eCipher.init(Cipher.ENCRYPT_MODE, eKey, eIvParameterSpec, random); 
        
	    InputStream clearTextFis = new FileInputStream(uploadedFile);
	    OutputStream cipherTextFos = new FileOutputStream(encryptedFile);
        
	    cipherTextFos = new CipherOutputStream(cipherTextFos, eCipher);
	    byte[] ebuf = new byte[4096];
        int enumRead = 0;
        while ((enumRead = clearTextFis.read(ebuf)) >= 0) {
        	cipherTextFos.write(ebuf, 0, enumRead);
        }
        cipherTextFos.close();       
	}
	
	/*
	 * Decrypt using password based encryption
	 */
	public static void decrypt(EncryptionKeys encryptionKeys, InputStream s3is, File decryptedFile, String passphrase) throws Exception{
    	Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); 
        
    	SecureRandom random = new SecureRandom();
    	String secretKeyType = "PBEWITHSHA256AND256BITAES-CBC-BC";
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(secretKeyType); 

        PBEKeySpec dKeySpec = new PBEKeySpec(DigestUtils.md5Hex(passphrase).toCharArray(), encryptionKeys.getSaltBytes(), 
        		encryptionKeys.getIterationCount(), 1024); 
        SecretKey dKey = keyFactory.generateSecret(dKeySpec); 
        Cipher dCipher = Cipher.getInstance("AES/CTR/NOPADDING"); 
        IvParameterSpec dIvParameterSpec =  new IvParameterSpec(encryptionKeys.getIvBytes()); 
        dCipher.init(Cipher.DECRYPT_MODE, dKey, dIvParameterSpec, random); 
        
	    OutputStream decryptedTextFos = new FileOutputStream(decryptedFile);

	    s3is = new CipherInputStream(s3is, dCipher);
        
        int dnumRead = 0;
        byte[] dbuf = new byte[4096];
        while ((dnumRead = s3is.read(dbuf)) >= 0) {
        	decryptedTextFos.write(dbuf, 0, dnumRead);
        }
        decryptedTextFos.close();
	}
}